package com.ng.predictor;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

public class AdvancedDicePredictorWithAutoTuning {
    // 自然概率表 (和值3-18)
    private static final Map<Integer, Double> NATURAL_PROBS = new HashMap<>();
    static {
        NATURAL_PROBS.put(3, 1.0/216);
        NATURAL_PROBS.put(4, 3.0/216);
        NATURAL_PROBS.put(5, 6.0/216);
        NATURAL_PROBS.put(6, 10.0/216);
        NATURAL_PROBS.put(7, 15.0/216);
        NATURAL_PROBS.put(8, 21.0/216);
        NATURAL_PROBS.put(9, 25.0/216);
        NATURAL_PROBS.put(10, 27.0/216);
        NATURAL_PROBS.put(11, 27.0/216);
        NATURAL_PROBS.put(12, 25.0/216);
        NATURAL_PROBS.put(13, 21.0/216);
        NATURAL_PROBS.put(14, 15.0/216);
        NATURAL_PROBS.put(15, 10.0/216);
        NATURAL_PROBS.put(16, 6.0/216);
        NATURAL_PROBS.put(17, 3.0/216);
        NATURAL_PROBS.put(18, 1.0/216);
    }

    // 历史数据存储
    private final LinkedList<Integer> history = new LinkedList<>();
    
    // 动态参数
    private double alpha = 0.5;  // 自然概率权重
    private double beta = 0.3;   // 冷门指数权重
    private double gamma = 0.1;  // 奇偶分析权重
    private double delta = 0.1;  // 冷热分析权重
    private int window = 10;     // 时间窗口大小
    private double learningRate = 0.1;
    
    // 参数边界
    private static final double MIN_ALPHA = 0.2;
    private static final double MAX_ALPHA = 0.8;
    private static final int MIN_WINDOW = 5;
    private static final int MAX_WINDOW = 20;

    // 预测记录（用于参数优化）
    private final List<PredictionRecord> predictionLog = new ArrayList<>();

    /**
     * 记录每次预测结果
     */
    private static class PredictionRecord {
        final List<Integer> predictedTop3;
        final int actualSum;
        final LocalDateTime timestamp;

        PredictionRecord(List<Integer> predictedTop3, int actualSum) {
            this.predictedTop3 = new ArrayList<>(predictedTop3);
            this.actualSum = actualSum;
            this.timestamp = LocalDateTime.now();
        }
        
        boolean isHit() {
            return predictedTop3.contains(actualSum);
        }
    }

    /**
     * 新增开奖结果并优化模型
     */
    public void addResultAndOptimize(int actualSum) {
        // 记录最新结果
        history.add(actualSum);
        if (history.size() > MAX_WINDOW * 2) {
            history.removeFirst();
        }

        // 如果有预测记录则进行优化
        if (!predictionLog.isEmpty()) {
            optimizeParameters();
        }

        // 检测连续三期不中
        if (predictionLog.size() >= 3) {
            boolean lastThreeMissed = true;
            for (int i = predictionLog.size() - 3; i < predictionLog.size(); i++) {
                if (predictionLog.get(i).isHit()) {
                    lastThreeMissed = false;
                    break;
                }
            }
            if (lastThreeMissed) {
                System.out.println("连续三期未命中，触发参数优化...");
                autoTuneParameters();
                // 参数优化后立即输出下一期预测
                printNextPrediction();
            }
        }
    }

    /**
     * 参数优化核心逻辑
     */
    private void optimizeParameters() {
        // 1. 计算近期准确率
        double recentAccuracy = calculateRecentAccuracy(10);
        
        // 2. 动态调整时间窗口
        if (recentAccuracy < 0.3) {
            window = Math.min(window + 2, MAX_WINDOW);
        } else if (recentAccuracy > 0.6) {
            window = Math.max(window - 1, MIN_WINDOW);
        }

        // 3. 梯度下降调整alpha/beta/gamma/delta
        double gradientAlpha = calculateGradient(MIN_ALPHA, MAX_ALPHA);
        double gradientBeta = calculateGradient(0, 1 - alpha - gamma - delta);
        double gradientGamma = calculateGradient(0, 1 - alpha - beta - delta);
        double gradientDelta = calculateGradient(0, 1 - alpha - beta - gamma);
        
        alpha = clamp(alpha + learningRate * gradientAlpha, MIN_ALPHA, MAX_ALPHA);
        beta = clamp(beta + learningRate * gradientBeta, 0, 1 - alpha - gamma - delta);
        gamma = clamp(gamma + learningRate * gradientGamma, 0, 1 - alpha - beta - delta);
        delta = clamp(delta + learningRate * gradientDelta, 0, 1 - alpha - beta - gamma);

        // 4. 清理旧记录
        predictionLog.removeIf(record -> 
            record.timestamp.isBefore(LocalDateTime.now().minusDays(7)));
    }

    /**
     * 自动调整参数（网格搜索）
     */
    private void autoTuneParameters() {
        double bestAlpha = alpha;
        double bestBeta = beta;
        double bestGamma = gamma;
        double bestDelta = delta;
        double bestScore = calculateRecentAccuracy(20);

        // 网格搜索参数组合
        for (double a = MIN_ALPHA; a <= MAX_ALPHA; a += 0.1) {
            for (double b = 0.0; b <= 1 - a; b += 0.1) {
                for (double g = 0.0; g <= 1 - a - b; g += 0.1) {
                    double d = 1 - a - b - g;
                    alpha = a;
                    beta = b;
                    gamma = g;
                    delta = d;

                    double score = calculateRecentAccuracy(20);
                    if (score > bestScore) {
                        bestScore = score;
                        bestAlpha = a;
                        bestBeta = b;
                        bestGamma = g;
                        bestDelta = d;
                    }
                }
            }
        }

        // 更新最优参数
        alpha = bestAlpha;
        beta = bestBeta;
        gamma = bestGamma;
        delta = bestDelta;
        System.out.printf("参数优化完成: α=%.2f β=%.2f γ=%.2f δ=%.2f\n", alpha, beta, gamma, delta);
    }

    /**
     * 计算参数梯度
     */
    private double calculateGradient(double min, double max) {
        // 简化的梯度计算（可根据需要扩展为复杂策略）
        return predictionLog.stream()
            .mapToDouble(record -> record.isHit() ? 0.1 : -0.1)
            .average()
            .orElse(0.0);
    }

    /**
     * 计算近期预测准确率
     */
    private double calculateRecentAccuracy(int lookBack) {
        int hitCount = 0;
        int total = Math.min(lookBack, predictionLog.size());
        
        for (int i = predictionLog.size() - total; i < predictionLog.size(); i++) {
            if (predictionLog.get(i).isHit()) {
                hitCount++;
            }
        }
        return (double) hitCount / total;
    }

    /**
     * 带自适应的预测方法
     */
    public List<Integer> adaptivePredict() {
        List<Integer> prediction = predictTop3();
        
        // 记录预测结果（实际结果需后续通过addResultAndOptimize添加）
        predictionLog.add(new PredictionRecord(
            prediction, 
            history.isEmpty() ? -1 : history.getLast())
        );
        
        return prediction;
    }

    /**
     * 预测概率最高的三个和值
     */
    public List<Integer> predictTop3() {
        Map<Integer, Double> coldIndex = calculateColdIndex();
        Map<Integer, Double> parityBias = calculateParityBias();
        Map<Integer, Double> hotColdBias = calculateHotColdBias();

        // 计算综合概率
        List<Map.Entry<Integer, Double>> combined = new ArrayList<>();
        for (int sum = 3; sum <= 18; sum++) {
            double natural = NATURAL_PROBS.get(sum);
            double cold = coldIndex.get(sum);
            double parity = parityBias.get(sum);
            double hotCold = hotColdBias.get(sum);
            double score = alpha * natural + beta * cold + gamma * parity + delta * hotCold;
            combined.add(new AbstractMap.SimpleEntry<>(sum, score));
        }

        // 排序并取前三
        return combined.stream()
            .sorted((e1, e2) -> e2.getValue().compareTo(e1.getValue()))
            .limit(3)
            .map(Map.Entry::getKey)
            .collect(Collectors.toList());
    }

    /**
     * 计算冷门指数
     */
    private Map<Integer, Double> calculateColdIndex() {
        Map<Integer, Integer> countMap = new HashMap<>();
        
        // 初始化计数器
        for (int sum = 3; sum <= 18; sum++) {
            countMap.put(sum, 0);
        }

        // 获取最近window期数据
        List<Integer> recentData = history.subList(
            Math.max(history.size() - window, 0), 
            history.size()
        );

        // 统计出现次数
        for (int sum : recentData) {
            countMap.put(sum, countMap.get(sum) + 1);
        }

        // 计算冷门指数
        Map<Integer, Double> coldIndex = new HashMap<>();
        for (int sum = 3; sum <= 18; sum++) {
            int count = countMap.get(sum);
            coldIndex.put(sum, 1.0 / (count + 1));
        }
        return coldIndex;
    }

    /**
     * 计算奇偶分析权重
     */
    private Map<Integer, Double> calculateParityBias() {
        // 统计近期奇偶和值的比例
        long oddCount = history.stream()
            .filter(sum -> sum % 2 == 1)
            .count();
        long evenCount = history.size() - oddCount;
        
        // 计算奇偶偏差
        double oddBias = (double) oddCount / history.size();
        double evenBias = (double) evenCount / history.size();
        
        // 分配权重
        Map<Integer, Double> parityBias = new HashMap<>();
        for (int sum = 3; sum <= 18; sum++) {
            parityBias.put(sum, sum % 2 == 1 ? oddBias : evenBias);
        }
        return parityBias;
    }

    /**
     * 计算冷热分析权重
     */
    private Map<Integer, Double> calculateHotColdBias() {
        // 统计所有历史数据中每个和值的出现频率
        Map<Integer, Integer> totalCountMap = new HashMap<>();
        for (int sum = 3; sum <= 18; sum++) {
            totalCountMap.put(sum, 0);
        }
        for (int sum : history) {
            totalCountMap.put(sum, totalCountMap.get(sum) + 1);
        }

        // 计算冷热指数
        double maxCount = Collections.max(totalCountMap.values());
        Map<Integer, Double> hotColdBias = new HashMap<>();
        for (int sum = 3; sum <= 18; sum++) {
            double frequency = (double) totalCountMap.get(sum) / history.size();
            hotColdBias.put(sum, frequency / maxCount); // 归一化到[0,1]
        }
        return hotColdBias;
    }

    /**
     * 限制参数范围
     */
    private double clamp(double value, double min, double max) {
        return Math.max(min, Math.min(max, value));
    }

    /**
     * 输出下一期预测信息
     */
    public void printNextPrediction() {
        List<Integer> prediction = adaptivePredict();
        Map<Integer, Double> probabilities = calculateProbabilities();
        
        System.out.println("===== 下一期预测信息 =====");
        System.out.println("预测和值（Top 3）: " + prediction);
        System.out.println("和值概率分布:");
        for (int sum = 3; sum <= 18; sum++) {
            System.out.printf("和值 %2d: %.2f%%\n", sum, probabilities.get(sum) * 100);
        }
        System.out.printf("当前参数: α=%.2f β=%.2f γ=%.2f δ=%.2f window=%d\n",
            alpha, beta, gamma, delta, window);
        System.out.println("=======================");
    }

    /**
     * 计算所有和值的综合概率
     */
    private Map<Integer, Double> calculateProbabilities() {
        Map<Integer, Double> coldIndex = calculateColdIndex();
        Map<Integer, Double> parityBias = calculateParityBias();
        Map<Integer, Double> hotColdBias = calculateHotColdBias();

        Map<Integer, Double> probabilities = new HashMap<>();
        for (int sum = 3; sum <= 18; sum++) {
            double natural = NATURAL_PROBS.get(sum);
            double cold = coldIndex.get(sum);
            double parity = parityBias.get(sum);
            double hotCold = hotColdBias.get(sum);
            double score = alpha * natural + beta * cold + gamma * parity + delta * hotCold;
            probabilities.put(sum, score);
        }
        return probabilities;
    }

    public static void main(String[] args) {
        AdvancedDicePredictorWithAutoTuning predictor = new AdvancedDicePredictorWithAutoTuning();
        
        // 模拟连续预测过程
        int[] actualResults = {7,9,15,11,12,12,11,8,16,11,12,9,6,7,14,6,12,7,13,11,12};
        
        for (int result : actualResults) {
            // 输出下一期预测信息
            predictor.printNextPrediction();
            
            // 反馈结果并优化
            predictor.addResultAndOptimize(result);
        }
    }
}